package com.yc.game;

import java.util.Scanner;

public class LLKGame {

	char[][] map;
	int x, y, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
	static Scanner sc = new Scanner(System.in);
	LLKGameListener llkGameListener = new LLKGameListener() {
	};

//	public static void main(String[] args) {
//		LLKGame game = new LLKGame();
//		game.build(5, 6);
//		while (true) {
//			game.print();
//			System.out.print("按下 W A S D 移动, 按下 Y 表示选择!");
//			String s = sc.nextLine();
//			if (s.length() == 0) {
//				game.choose();
//			} else {
//				switch (s.charAt(0)) {
//				case 'a':
//				case 'A':
//					game.move(-1, 0);
//					break;
//				case 'd':
//				case 'D':
//					game.move(1, 0);
//					break;
//				case 'W':
//				case 'w':
//					game.move(0, -1);
//					break;
//				case 's':
//				case 'S':
//					game.move(0, 1);
//					break;
//				case 'y':
//				case 'Y':
//					game.choose();
//					break;
//				}
//			}
//		}
//	}

	public void build(int width, int height) {
		if (width % 2 != 0 && height % 2 != 0) {
			throw new RuntimeException("宽度和高度必须有一个是偶数!");
		}
		map = new char[height][width];
		for (int i = 0; i < width * height; i += 2) {
			int j = (int) (Math.random() * 5);
			char c = (char) ('A' + j);
			int x = i % width;
			int y = i / width;
			map[y][x] = c;
			x = (i + 1) % width;
			y = (i + 1) / width;
			map[y][x] = c;
		}
		llkGameListener.onbegin(width, height);
		for (int y = 0; y < map.length; y++) {
			for (int x = 0; x < map[y].length; x++) {
				int xx = (int) (Math.random() * map[y].length);
				int yy = (int) (Math.random() * map.length);
				char c = map[y][x];
				map[y][x] = map[yy][xx];
				map[yy][xx] = c;
				llkGameListener.oninit(x, y, map[y][x]);
				llkGameListener.oninit(xx, yy, map[yy][xx]);
			}
		}
	}

	void print() {
		System.out.println("====================================");
		System.out.println("=               连连看              =");
		System.out.println("====================================");
		for (int y = 0; y < map.length; y++) {
			for (int x = 0; x < map[y].length; x++) {
				if (this.x1 == x && this.y1 == y)
					System.out.print("(");
				else if (this.x2 == x && this.y2 == y)
					System.out.print("(");
				else if (this.x == x && this.y == y)
					System.out.print("[");
				else
					System.out.print(" ");
				System.out.print(map[y][x]);
				if (this.x1 == x && this.y1 == y)
					System.out.print(")");
				else if (this.x2 == x && this.y2 == y)
					System.out.print(")");
				else if (this.x == x && this.y == y)
					System.out.print("]");
				else
					System.out.print(" ");

			}
			System.out.println();
		}
		System.out.println("====================================");
	}

	void move(int ox, int oy) {
		int x = this.x + ox;
		int y = this.y + oy;
		if (isValid(x, y)) {
			this.x = x;
			this.y = y;
		}
	}

	void choose(int x, int y) {
		if (x1 == -1) {
			x1 = x;
			y1 = y;
			llkGameListener.onchoose(x1, y1);
		} else {
			x2 = x;
			y2 = y;
			llkGameListener.onchoose(x2, y2);
		}
		if (x1 > -1 && x2 > -1) {
			if (connect()) {
				map[y1][x1] = map[y2][x2] = ' ';
				llkGameListener.ondisappe(x1, y1);
				llkGameListener.ondisappe(x2, y2);
			} else {
				llkGameListener.oncancel(x1, y1);
				llkGameListener.oncancel(x2, y2);
			}
			x1 = x2 = y1 = y2 = -1;
		}
		print();
	}

	void choose() {
		if (map[y][x] == ' ') {
			return;
		}
		if (x1 == -1) {
			x1 = x;
			y1 = y;
			llkGameListener.onchoose(x1, y1);
		} else {
			x2 = x;
			y2 = y;
			llkGameListener.onchoose(x2, y2);
		}
		if (x1 > -1 && x2 > -1) {
			if (connect()) {
				map[y1][x1] = map[y2][x2] = ' ';
				llkGameListener.ondisappe(x1, y1);
				llkGameListener.ondisappe(x2, y2);
			} else {
				llkGameListener.oncancel(x1, y1);
				llkGameListener.oncancel(x2, y2);
			}
			x1 = x2 = y1 = y2 = -1;
		}
	}

	boolean connect() {
		if (map[y1][x1] != map[y2][x2])
			return false;
		boolean ret = false;
		if (x1 == x2 || y1 == y2) {
			ret = connect1(x1, y1, x2, y2) || connect3(x1, y1, x2, y2);
		} else if (map[y1][x2] == ' ' || map[y2][x1] == ' ') {
			ret = connect2(x1, y1, x2, y2);
		} else {
			ret = connect3(x1, y1, x2, y2);
		}
		return ret;
	}

	// 一折线(直线)连接
	boolean connect1(int x1, int y1, int x2, int y2) {
		if (y1 == y2) {
			if (y1 == 0 || y1 == map.length - 1)
				return true;
			int begin = Math.min(x1, x2);
			int end = Math.max(x1, x2);
			for (int i = begin + 1; i < end; i++) {
				if (map[y1][i] != ' ') {
					return false;
				}
			}
			return true;
		} else {
			if (x1 == 0 || x1 == map[y1].length - 1)
				return true;
			int begin = Math.min(y1, y2);
			int end = Math.max(y1, y2);
			for (int i = begin + 1; i < end; i++) {
				if (map[i][x1] != ' ') {
					return false;
				}
			}
			return true;
		}
	}

	// 2折线连接(1个弯) 测试与相交点的连通
	boolean connect2(int x1, int y1, int x2, int y2) {
		int xx1 = x1;
		int yy1 = y2;
		if (connect1(x1, y1, xx1, yy1) && connect1(x2, y2, xx1, yy1)) {
			return true;
		}
		int xx2 = x2;
		int yy2 = y1;
		if (connect1(x1, y1, xx2, yy2) && connect1(x2, y2, xx2, yy2)) {
			return true;
		}
		return false;
	}

	// 3折线连接(2个弯) 测试与相交点路径上每一个点的连通
	boolean connect3(int x1, int y1, int x2, int y2) {
		for (int x = 0; x < map[y1].length; x++) {
			// 先测试 1折线 再测试 2折线
			if (map[y1][x] == ' ' && connect1(x1, y1, x, y1) && connect2(x2, y2, x, y1)) {
				return true;
			}
		}
		for (int y = 0; y < map.length; y++) {
			// 先测试 1折线 再测试 2折线
			if (map[y][x1] == ' ' && connect1(x1, y1, x1, y) && connect2(x2, y2, x1, y)) {
				return true;
			}
		}
		return false;
	}

	// 判断坐标是否合法
	boolean isValid(int x, int y) {
		return !(x < 0 || y < 0 || y >= map.length || x >= map[y].length);
	}

	public void setLlkGameListener(LLKGameListener llkGameListener) {
		this.llkGameListener = llkGameListener;
	}

	public static interface LLKGameListener {
		default void oninit(int x, int y, char c) {
		}

		default void onchoose(int x, int y) {
		}

		default void oncancel(int x, int y) {
		}

		default void ondisappe(int x, int y) {
		}

		default void onbegin(int width, int height) {
		}
	}

}
